import json
import re
from datetime import datetime
import asyncio

import requests
from urllib import parse
from django.http import HttpResponse, JsonResponse
from django.conf import settings
from django.contrib.auth import hashers
from django.db import transaction
from django.db.models import F
from rest_framework import mixins, viewsets
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView, Response, status
from asgiref.sync import sync_to_async

from apps.common.account.models import Account, AccountRoles, MiniprogramAccount
# from apps.common.account.views import get_tokens_for_user
from apps.common.account.views import get_tokens_for_user
from apps.common.mini_program.serializers import UserSerializer


def get_openid(code):
    """ 微信根据code 获取openid"""
    url = f"https://api.weixin.qq.com/sns/jscode2session?appid={settings.APP_ID}&secret={settings.APP_SECRET}&js_code" \
          f"={code}&grant_type=authorization_code"
    result = requests.get(url)
    res = json.loads(result.text)  # 得到的数据格式为：{'session_key': '', 'openid': ''}
    openid = res.get('openid', None)
    return openid


def get_role(user):
    """
    0-tourist（游客）1-member（社团成员） 2-secretary（团支书） 3-chairman（会长） 4-adviser（指导老师） 5-school_committee（校团委）
    """
    role = ['member']

    return role


# 是否能看到小程序我的页面的测评统计功能，只有模块管理员和超级管理员能看
def see_survey_statistics(user):
    if user.is_admin():
        return True
    if AccountRoles.objects.filter(role__name__icontains='管理员', account=user).exists():
        return True
    return  False


def dgut_new_auth(username, password):
    """
        调用学校的新统一认证restful接口
        return: 字典，code为200表示认证成功，字典携带uid返回, code不为200表示认证失败
    """
    appid = settings.NEW_APPID
    service = settings.NEW_URL

    # 1. 获取 access_token
    access_token_url = f"https://auth-gateway.dgut.edu.cn/token/gateway/{appid}/accessToken"
    r = requests.get(access_token_url)  # get请求获取登陆页面
    if r.status_code != 200:
        return {'code': 400, 'message': '获取access_token出错，请联系开发人员'}
    res_data = json.loads(r.text)
    access_token = res_data.get('data', '')
    if not access_token:
        return {'code': 400, 'message': '获取access_token出错，请联系开发人员'}

    # 对密码进行 AES加密
    from .utils import Encrypt
    a = Encrypt(key=settings.NEW_PWD, iv=settings.NEW_IV)
    jiami_password = a.aes_encrypt(password)  # 加密后的密码

    # 2. 通过 access_token 获取用户信息
    url = f"https://auth-gateway.dgut.edu.cn/authserver/v1/users"
    post_data = {'username': username, 'service': service, 'password': jiami_password}
    headers = {'Content-Type': 'application/x-www-form-urlencoded', 'appId': appid, 'accessToken': access_token}
    r = requests.post(url, data=post_data, headers=headers)
    if r.status_code != 200:
        return {'code': 400, 'message': '账号或密码错误'}
    res_data = json.loads(r.text)
    realname = res_data.get('cn', '')
    uid = res_data.get('uid', '')
    if isinstance(uid, list):
        uid = uid[0]
    if isinstance(realname, list):
        realname = realname[0]

    if not uid:
        return {'code': 400, 'message': '账号或密码错误'}

    return {'code': 200, 'message': '成功', 'uid': uid, 'realname': realname}


class WechatLoginView(APIView):

    def post(self, request):
        """ 微信登陆 """
        code = request.data.get('code', None)
        if not code:
            return Response({'message': '缺少code'}, status=status.HTTP_400_BAD_REQUEST)
        openid = get_openid(code)
        if not openid:
            return Response({'message': '请求微信服务器失败，请重试'}, status=status.HTTP_503_SERVICE_UNAVAILABLE)

        wechat_account = MiniprogramAccount.objects.filter(mini_program_openid=openid).first()
        if not wechat_account:
            return Response({'openid': openid, 'message': '找不到该微信用户'}, status=status.HTTP_400_BAD_REQUEST)
        user = wechat_account.account  # 获取该微信账号绑定的用户
        data = get_tokens_for_user(user)
        user.last_login = datetime.now()  # 修改该账号的最近登陆时间
        user.save()
        data['is_see'] = see_survey_statistics(user)
        data['openid'] = openid
        data['faculty'] = user.faculty_title
        data['username'] = user.username
        data['realname'] = user.realname
        data['wx_photo'] = f"{settings.FILE_URL}{user.wx_photo}" if user.wx_photo else ''
        return Response({'data': data, 'message': '登录成功'}, status=status.HTTP_200_OK)


class NewBindView(APIView):

    def post(self, request):
        """ 绑定 """
        service = 'https://survey-api.dgut.edu.cn/miniprogram'
        openid = request.data.get('openid', None)
        ticket = request.data.get('ticket', None)
        if not all([openid, ticket]):
            return Response({'message': '缺少参数'}, status=status.HTTP_400_BAD_REQUEST)

        existed = MiniprogramAccount.objects.filter(mini_program_openid=openid).exists()
        if existed:
            return Response({'message': '错误，该微信已绑定账号, 一个微信只支持绑定一个账号。'},
                            status=status.HTTP_400_BAD_REQUEST)

        # 验证st票据
        validate_url = f'https://auth.dgut.edu.cn/authserver/serviceValidate?ticket={ticket}&service={service}'
        res = requests.get(validate_url)
        from xml.dom.minidom import parseString
        dom = parseString(res.text)
        root = dom.documentElement
        try:
            username = root.getElementsByTagName('cas:user')[0].childNodes[0].data
            realname = root.getElementsByTagName('cas:userName')[0].childNodes[0].data
        except Exception:
            return Response({'message': '登录失败！'}, status=status.HTTP_400_BAD_REQUEST)

        # 查询该用户并绑定，如果该用户不在就去学校给的用户数据找
        try:
            user = Account.objects.get(username=username)
        except Account.DoesNotExist:
            from apps.common.account.models import Yhsjb
            try:
                user_info = Yhsjb.objects.get(username=username)
                user = Account.objects.create(username=username, realname=user_info.realname if user_info.realname else '',
                                              sex=user_info.sex if user_info.sex else '',
                                              faculty_code=user_info.faculty_code if user_info.faculty_code else '',
                                              faculty_title=user_info.faculty_title if user_info.faculty_title else '',
                                              telephone=user_info.telephone if user_info.telephone else '',
                                              status=user_info.status if user_info.status else '',
                                              grade_name=user_info.grade_name if user_info.grade_name else '',
                                              type=user_info.type if user_info.type else '',
                                              major_code=user_info.major_code if user_info.major_code else '',
                                              major_title=user_info.major_title if user_info.major_title else '',
                                              class_code=user_info.class_code if user_info.class_code else '',
                                              class_title=user_info.class_title if user_info.class_title else '',
                                              )
            except Yhsjb.DoesNotExist:
                user = Account.objects.create(username=username, realname=realname)
            except Exception:
                user = Account.objects.create(username=username, realname=realname)

            # 将该微信与系统中的账号绑定
        MiniprogramAccount.objects.create(mini_program_openid=openid, account=user)
        # 返回jwt和用户的数据
        data = get_tokens_for_user(user)
        data['is_see'] = see_survey_statistics(user)
        data['faculty'] = user.faculty_title
        data['username'] = user.username
        data['realname'] = user.realname
        return Response({'data': data, 'message': '绑定成功'}, status=status.HTTP_200_OK)


class UnBindAccountView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        """ 解绑账号 """
        user = request.user
        openid = request.data.get('openid', None)
        if not openid:
            return Response({'message': '需要openid'}, status=status.HTTP_400_BAD_REQUEST)

        MiniprogramAccount.objects.filter(account=user, mini_program_openid=openid).delete()
        return Response({'message': '解绑账号成功'}, status=status.HTTP_200_OK)


class MiniProgramBindAccount(APIView):

    def post(self, request):
        """ 传入账号密码，将该账号与该用户的小程序绑定 """
        username = request.data.get('username', '')
        password = request.data.get('password', '')
        mini_program_openid = request.data.get('openid', '')
        if not all([username, password, mini_program_openid]):
            return Response({'message': '错误，必须输入账号和密码。'}, status=status.HTTP_400_BAD_REQUEST)
        existed = MiniprogramAccount.objects.filter(mini_program_openid=mini_program_openid).exists()
        if existed:
            return Response({'message': '错误，该微信已绑定账号, 一个微信只支持绑定一个账号。'},
                            status=status.HTTP_400_BAD_REQUEST)

        # appid = settings.NEW_DD_REPAIR_APPID
        # service = settings.NEW_DD_REPAIR_URL

        # 调用学校新统一认证登录的 restful 接口
        res = dgut_new_auth(username, password)
        if res['code'] != 200:
            return Response({'message': res['message']}, status=res['code'])

        uid = res['uid']
        realname = res['realname']
        print(realname, uid)

        # 查询该用户并绑定，如果该用户不在就去学校给的用户数据找
        try:
            user = Account.objects.get(username=uid)
        except Account.DoesNotExist:
            user = Account.objects.create(username=uid, realname=realname)

        # 将该微信与系统中的账号绑定
        MiniprogramAccount.objects.create(mini_program_openid=mini_program_openid, account=user)
        # 返回jwt和用户的数据
        data = get_tokens_for_user(user)
        data['is_see'] = see_survey_statistics(user)
        data['faculty'] = user.faculty_title
        data['username'] = user.username
        data['realname'] = user.realname
        return Response({'data': data, 'message': '绑定成功'}, status=status.HTTP_200_OK)


class UserInformationViewSet(mixins.RetrieveModelMixin,
                             mixins.UpdateModelMixin,
                             viewsets.GenericViewSet):

    permission_classes = [IsAuthenticated]
    serializer_class = UserSerializer

    def get_queryset(self):
        return Account.objects.filter(user=self.request.user)

    @action(methods=['get'], detail=False, url_path='get_userdata')
    def get_my_user_data(self, request, *args, **kwargs):
        """ 获取个人信息"""
        user = request.user
        self.kwargs.setdefault('context', self.get_serializer_context())
        serializer = UserSerializer(user, **self.kwargs)
        return Response(serializer.data, status=status.HTTP_200_OK)

    def create(self, request, *args, **kwargs):
        """ 修改个人的信息 """
        # sex = request.data.get('sex', None)
        politics_status = request.data.get('politics_status', None)
        wechat_code = request.data.get('wechat_code', None)
        student_community = request.data.get('student_community', None)
        photo = request.data.get('photo', None)
        delete_image = request.data.get('delete_image', None)

        print(photo, delete_image)
        user = request.user
        if delete_image:
            user.photo.delete() if user.photo else ''
        # user.sex = sex
        user.politics_status = politics_status
        user.wechat_code = wechat_code
        user.student_community = student_community
        user.photo = photo
        user.save()
        return Response({'message': '完善成功'}, status=status.HTTP_200_OK)


class MiniUrlView(APIView):

    def get(self, request):
        """ 获取小程序中央认证登录的路径 """
        login_url = settings.MINI_PROGRAM_BACKEND_URL
        logout_url = settings.MINI_PROGRAM_LOGOUT_URL
        return Response({'login_url': login_url, 'logout_url': logout_url}, status=status.HTTP_200_OK)